// package Data Transform Object及衍生数据结构的定义，以及DTO本身的密码学验证：哈希、签名、序列化、反序列化
package dto

// const 账户相关的状态码
//  @param CODE_ACCOUNT_EXIST 账户存在
//  @param CODE_ACCOUNT_NOT_EXIST 账户不存在
const (
	CODE_ACCOUNT_EXIST     = 2001
	CODE_ACCOUNT_NOT_EXIST = 2002
)

// AccountStateDto 传输账户状态数据
type AccountStateDto struct {

	// BaseDto
	BaseDto

	// PrivKeyStr ecdsa私钥字符串
	PrivKeyStr string `json:"privKeyStr"`

	// AcountAddr 账户地址
	AcountAddr string `json:"accountAddr"`

	// Asset 账户余额
	Asset int64 `json:"asset"`

	// CoinSince 用于计算币龄（=time.Now().Unix()-CoinSince）
	CoinSince int64 `json:"coinSince"`

	// Nonce 初始随机数
	Nonce int64 `json:"nonce"`

	// MaxNonce 随机数最大值（超过这个值从0继续）
	MaxNonce int64 `json:"maxNonce"`
}

// StateLeaf 状态树叶子节点的数据结构
type StateLeaf struct {

	// Asset 账户余额
	Asset int64 `json:"asset"`

	//TODO
	// CoinSince 账户资产的平均货币出厂时间戳（用于计算平均币龄=time.Now().Unix()-CoinSince）
	CoinSince int64 `json:"coinSince"`

	// Nonce 当前账户的随机数
	Nonce int64 `json:"nonce"`

	// MaxNonce 随机数最大值（超过这个值从0继续）
	MaxNonce int64 `json:"maxNonce"`

	// CoolDown 是否进入冷却期（节点获得记账权后，会进入至少一个时隙的冷却期，直到Asset全部通过release返还给各个账户）
	CoolDown bool `json:"coolDown"`

	// DataMap
	DataMap map[string]string `json:"datamap"`
}

// CommitAssetChange 变更账户的资产以及币龄
//  @receiver leaf
//  @param deltaAsset 资产变化量（正代表收入，负代表支出）
//  @param coinSince 资产变化量的coinSince
func (leaf *StateLeaf) CommitAssetChange(deltaAsset int64, coinSince int64) {
	//资产支出时对币龄不影响
	if deltaAsset <= 0 {
		leaf.Asset = leaf.Asset + deltaAsset
		return
	}

	//资产收入时，会用加权平均计算得到新的币龄
	avgSince := (int64)((leaf.Asset*leaf.CoinSince + deltaAsset*coinSince) / (leaf.Asset + deltaAsset))
	leaf.CoinSince = avgSince
	leaf.Asset = leaf.Asset + deltaAsset
}

// UndoAssetChange 和CommitAssetChange反过来
//  @receiver leaf
//  @param deltaAsset
//  @param coinSince
func (leaf *StateLeaf) UndoAssetChange(deltaAsset int64, coinSince int64) {
	//资产支出时对币龄不影响
	if deltaAsset <= 0 {
		leaf.Asset -= deltaAsset
		return
	}

	//资产收入时，会用加权平均计算得到新的币龄
	avgSince := (int64)((leaf.Asset*leaf.CoinSince - deltaAsset*coinSince) / (leaf.Asset - deltaAsset))
	leaf.CoinSince = avgSince
	leaf.Asset -= deltaAsset
}
